Skip to content

Feature: Upgrade Ruby to version 4.0.0#134

Merged
newstler merged 1 commit intomainfrom
feature/ruby-4.0.0
Jan 3, 2026
Merged

Feature: Upgrade Ruby to version 4.0.0#134
newstler merged 1 commit intomainfrom
feature/ruby-4.0.0

Conversation

@newstler
Copy link
Owner

@newstler newstler commented Jan 3, 2026

No description provided.

@newstler newstler merged commit 12bfd61 into main Jan 3, 2026
4 checks passed
newstler added a commit that referenced this pull request Feb 9, 2026
newstler added a commit that referenced this pull request Feb 9, 2026
* Feature: Upgrade Ruby to version 4.0.0

* Feature: Add testimonial system with AI-generated fields and home page carousel

Users can answer "Why do you love Ruby?" on their profile page. A two-job
AI pipeline (GenerateTestimonialFieldsJob → ValidateTestimonialJob) generates
structured fields (heading, subheading, body_text), validates content, and
auto-publishes. Headings are kept unique via AI retry with synonym generation.
Published testimonials display in a Stimulus-powered carousel on the home page
with auto-advance, arrow/dot navigation, and fade transitions.

Includes Avo admin resource, invitation mailer with rake task, seed data with
4 pre-published testimonials, and full test coverage.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Almost styled carousel

* Styled main carousel

* Almost finished with testimonials carousel

* Styling user profile testimonial

* Editing testimonials

* Validating testimonial

* Validating testimonial

* Add humanizer guidelines to testimonial LLM prompts and reject_reason flow

Embed writing style guidelines into GenerateTestimonialFieldsJob and
AI-sounding language checks into ValidateTestimonialJob so generated
testimonial text reads naturally. Add reject_reason column to distinguish
quote vs generation rejections, improve validation prompt with content
policy and structured reject reasons, and refine form UI with pill-style
character counter and turbo stream placement fix.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix timer reset in slider

* Almost fixed user in carousel

* Styled user info everywhere

* Replaced circle avatars with ruby-shaped

* Fix company/location filtering bug

* Added infinite scroll to users

* Stick header in community

* Feature: Add big + button in every content page

* Improve testimonial carousel mobile experience and update deployment config

- Add swipe gesture support and navigation dots for mobile carousel
- Make testimonial layout responsive with stacked view on mobile/tablet
- Add compact mode to user tiles for testimonial display
- Show mobile CTA button when testimonial section nav is hidden
- Fix sticky header on community page to not stick on horizontal phones
- Hide empty tabs on user profile pages
- Update deploy.yml to use local registry and new.whyruby.info domain

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix deploy.yml

* Styled User profile on mobile

* Migrate from ULID to UUIDv7 primary keys

- Replace sqlite-ulid gem with sqlean for UUIDv7 support
- Update database.yml to use SQLean::UUID extension
- Remove obsolete ULID initializers (sqlite.rb, active_storage_ulid.rb)
- Add migration to switch all table defaults from ULID() to uuid7()
- Add rake task for transforming existing ULID data to UUIDv7
- Add data transfer verification tasks
- Update test fixtures to use UUIDv7 format

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Move to whyruby.info

* Add rubycommunity.org as separate domain for community pages

- Route rubycommunity.org to users#index as its own root
- Override header logo and navigation on community pages
- Add content_for blocks in layout for header customization
- Update deploy.yml to serve both whyruby.info and rubycommunity.org
- Fix total users count display in community header

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix community link

* Route OAuth through primary domain for multi-domain support

When users sign in from rubycommunity.org, redirect them through
whyruby.info for GitHub OAuth (since only one callback URL is allowed),
then redirect back to the community domain after successful auth.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* f

* Implement cross-domain OAuth with session sync for whyruby.info and rubycommunity.org

- Add separate GitHub OAuth apps per domain with dynamic setup in devise.rb
- Add cross_domain_token to users for one-time session sync tokens
- Create AuthController for receiving cross-domain auth tokens
- Update routes for rubycommunity.org users at root level (/:username)
- Centralize domain config in config/initializers/domains.rb
- Add cross_domain_url and community_index_url helpers
- Sign in redirects to user profile, sign out from community stays on community
- Disable Turbo on sign-out buttons for proper page refresh

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix cross-domain session sync and community logo URLs

- Fix logo 404 on rubycommunity.org by using community_index_url instead of users_path
- Don't show "Session sync failed" error when user is already signed in on target domain
- Memoize cross-domain token per request to avoid generating multiple tokens

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Styled community pages

* Update legal policies for multi-domain setup and reduce token expiration

Reflects the unified operation of whyruby.info and rubycommunity.org under
the same data controller. Documents the cross-domain authentication mechanism
and reduces the session sync token lifetime from 5 minutes to 30 seconds for
improved security.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Update community pages meta tags for rubycommunity.org branding

- Add community_page_title helper for "Ruby Community" titles
- Refactor versioned_og_image_url to accept filename parameter
- Update users index/show views to use community OG image and site name
- Add meta.community.site_name locale
- Update footer links with target="_blank" and "Hire me!" CTA

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix community page titles to use Ruby Community branding

- Add :full_title content_for support in layout for complete title override
- Users index: title and og:title now just "Ruby Community" (not redundant)
- Users show: title now "Ruby Community — [User Name]"

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Update community pages with proper Ruby Community branding

- Add :full_title support in layout for complete title override
- Add community_root_canonical_url and community_user_canonical_url helpers
- Fix PWA meta tags (application-name, apple-mobile-web-app-title) for community
- Use rubycommunity.org URLs in production for canonical/og:url tags
- Title: "Ruby Community" for index, "Ruby Community — [Name]" for profiles

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Replace Google Analytics with Nullitics

- Remove Google Analytics and Plausible scripts
- Add Nullitics privacy-first analytics (no cookies, no IP storage)
- Add noscript fallback for JS-disabled users
- Update cookie policy and privacy policy for Nullitics
- GDPR, ePrivacy, PECR, CCPA, and COPPA compliant

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix infinite scroll routing on rubycommunity.org domain

On the community domain, pagination requests to /community?page=2 were
being caught by the /:id route and interpreted as a user profile for
"community", causing 404 errors. Added community_index_path helper that
generates root path (/) on the community domain in production, and
/community elsewhere.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add country code tracking to Nullitics analytics

Use MaxMind GeoLite2 database for IP geolocation to send client country
code (ISO 3166-1 alpha-2) to Nullitics. Database is downloaded during
Docker build using MAXMIND_LICENSE_KEY from production credentials.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix company/location filter links on user profile page

Use community_index_path helper instead of users_path for filter links
so they generate "/" on rubycommunity.org in production instead of
"/community" which gets caught by the /:id route.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Upgraded Ruby version to 4.0.1

* Fix post URLs to always point to primary domain from community pages

Posts viewed from user profiles on rubycommunity.org were incorrectly
linking to that domain instead of whyruby.info. Added primary_domain_post_url
helper to ensure posts always link to the content domain in production.

Also removed unnecessary "uncategorized" fallbacks throughout the codebase
since posts always require a category (validated in model).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Allow empty quote

* Fix MaxMind API: require account_id for GeoLite2 download

  MaxMind changed their API in May 2024 to require HTTP Basic Auth
  with account_id and license_key instead of just license_key in URL.

  Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Updated favicon

* Fix user links to point to community domain in production

User profile links in posts, comments, and user tiles now correctly
link to rubycommunity.org instead of staying on whyruby.info.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix edit/delete post links to always use primary domain

In production, edit and delete buttons now link to whyruby.info
instead of staying on the current domain (rubycommunity.org).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix edit/delete links in post tiles to use primary domain

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Added Open to work

* Fix counters

* Fix stars

* Fix long company/location

* Linkify links in user bio

* Fix toggles on mobile

* Fix sign-in redirect to always go to rubycommunity.org profile

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Migrate GitHub data fetching to GraphQL with batching

Replace REST API calls with GitHub GraphQL API for batch processing:
- Fetch multiple users in single request (5 users per batch)
- Filter Ruby repos server-side using search query
- Auto-split batches on 502/503/504 errors with retry
- Reduce API calls from 140+ to ~15 for 74 users

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Optimize performance across controllers, views, and helpers

- Add comments_count counter cache to posts table to eliminate N+1 queries
- Cache geocoder lookups with Rails.cache (1 hour expiry)
- Memoize Redcarpet markdown renderer at class level
- Cache OG image file modification times at boot
- Use SQL RANDOM() instead of to_a.shuffle for testimonials
- Remove unnecessary includes in UsersController#index
- Add missing user/category includes in PostsController
- Change tags.pluck to tags.map to use preloaded data
- Extract column distribution logic to PostsHelper
- Precompute linkified bios on save with bio_html column
- Update counter cache rake task for posts.comments_count

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Updated community page

* Updated community page

* Styled logo to react on hover

* Add github production api key

* Refactor minimal nav into shared partial and fix testimonial tests

- Extract minimal nav pattern into shared/_minimal_nav.html.erb
- Update home page to use minimal nav with "Why ❤️ Ruby?" branding
- Add category navigation buttons to home page
- Simplify community nav to use the shared partial
- Fix testimonial tests to match model validation rules (140-320 char quotes)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Sticky menu on home page

* Sticky menu on home page

* Styled the menu on home page

* Fix UI

* Add newsletter mailer with tracking and admin notifications

- NewsletterMailer with versioned updates (prevents duplicate sends)
- AdminMailer for post hidden notifications
- SMTP configuration for production
- Browser preview delivery for development email testing
- Newsletter rake task with user filtering and tracking
- Flash controller for UI notifications

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Corrected the flash messages

* Add newsletter unsubscribe and improve email templates

- Add unsubscribe mechanism with signed tokens
- Fix red color to match website (#dc2626)
- Fix "Go try it!" URL to sign in and redirect to profile
- Use first name only in greeting
- Center the CTA button
- Make unsubscribe link more visible with separator
- Filter unsubscribed users in rake task

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Rewrite newsletter v1 with improved copy and formatting

- Rewrote content to highlight #1 Google ranking and testimonials feature
- Added personal photo and "Thanks for reading" signature
- Added links to official Ruby site, Vladimir's Twitter
- Made sites italic in separation explanation
- Added non-breaking spaces for better line breaks
- Improved personal note with AI integration focus
- Updated subject line

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Update newsletter subject line

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Keep only 3 app versions

* Fix Vladimir Dementyev name spelling

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add newsletter subscription toggle to profile settings

Users can now manage their newsletter subscription from their profile
page. Unsubscribe page links to the user's profile on rubycommunity.org.
Document multi-domain setup and canonical URL helpers in CLAUDE.md.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add newsletter open tracking via tracking pixel

Track which users opened each newsletter version using a 1x1 transparent
GIF pixel. Stats visible in Avo admin panel on user show page.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Feature: Upgrade Ruby to version 4.0.0 (#134)

* Update newsletter subject

* Add automated community OG image generation

Add /og-image-community route with a dedicated screenshot-optimized
template and a rake task (og:community) that uses headless Chrome
to capture the page at exactly 1200x630.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Update newsletter copy to invite community contributions

Replace "let me know" closing with open source invitation and link to
GitHub repo. Clean up old article draft versions, keep only v7.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix mailer

* Fix newsletter and article copy

- "their home page" → "its home page"
- Add commas: "Now, on your profile, you can" and "Along the way, I fixed"
- Add article: "or the 'Open to Work' badge"
- "became" → "has become" for present relevance

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* User avatar in design

* Add location normalization for community filtering

- Normalize freeform GitHub locations to "City, Country" format using Photon geocoder
- Add "Developers from other parts of [Country]" section with infinite scroll
- Section appears only after all main users are loaded
- Sorting applies to both main and other country sections
- Add country name translations via i18n

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add interactive community map with geocoded user locations

Extends the location normalizer to extract lat/lng coordinates from Photon
geocoding results and stores them on user records. Adds a Leaflet-based
interactive map to the community page with gem-shaped SVG avatar markers,
clustering, and "open to work" badges. Map data is served via a cached
JSON endpoint that works across the multi-domain setup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Tweak community map marker styling and cluster behavior

Increase marker border thickness for better visibility, adjust the
"open to work" badge position, and use spiderfy distance multiplier
instead of disabling clustering at a fixed zoom level.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Map affects the user list

* current user link on community page

* Styled community page

* Fix location normalizer missing city names and improve community map

LocationNormalizer now falls back to Photon's "name" property when
the result type is "city" (previously only checked "city" key, which
is absent for city-level results, causing fallback to country code only).
Replaced OpenStruct with Data.define. Also adjusts map zoom for mobile
and fixes sticky header behavior on horizontal tablets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add Open to work filter

* Fixes

* Replace locations rake tasks with single refresh task and use gem avatars consistently

Consolidated normalize and backfill_coordinates into a single
locations:refresh task that clears all data, re-normalizes, and
clears the map cache. Use gem avatar partial in comments, post
tiles, and post show page for consistent styling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* bug fixes

* Apply Rails performance patterns from RorVsWild article

Use collection rendering instead of loop rendering in views (~2x faster),
bulk job enqueuing with perform_all_later (~3.5x faster), .size instead
of .count on loaded relations, and .find_by/.take instead of .where.first.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Projects and trends

* Ready to deploy

* Add timezone-aware newsletter scheduling

Resolve user timezones from coordinates using wheretz gem so newsletter
emails arrive at 10:10 AM local time, spreading delivery across ~17 hours
instead of one burst.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add malicious path blocker middleware

Block common bot/scanner requests (wp-login, .env, .php, etc.) early
in the middleware stack before they hit Rails routing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Update article and newsletter with new community features

Add interactive map and daily star trends to the community section
copy. Remove daily star trends from future plans since it's shipped.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add sorting of projects to user profile

* UI fixes

* Fix legacy timezone identifiers breaking newsletter scheduling

The wheretz gem returns Europe/Kiev which newer tzdata packages
(like in our production Docker image) no longer recognize. Normalize
legacy IANA identifiers in TimezoneResolver and add a rake task to
fix existing stored data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Community UX improvements and cross-domain fixes

- Fix sign-out redirects between primary and community domains
- Add /community -> rubycommunity.org production redirects (301)
- Route footer legal links through main_site_url helper so they resolve correctly on community domain
- Default sort to "trending" instead of "top", reorder sort tabs
- Multi-token company search (e.g. "Basecamp 37signals" matches either)
- Linkify @Company mentions in company filter display
- Keep company filter when panning/zooming map
- Add mobile avatar link to profile in community header
- Add bio edit tooltip for profile owners
- Replace "gaining traction" with "popular" in newsletter and article draft

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add star trend display in admin and Avo resource controllers

Show daily stars gained next to star count in admin project index.
Add missing Avo resource controllers for projects, star snapshots,
and testimonials.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix brakeman security warnings and add brakeman to pre-commit hook

- Replace .html_safe with sanitize for bio_html output (XSS)
- Validate return_to redirect URLs against allowed domains (open redirect)
- Add brakeman to lefthook pre-commit checks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Update AGENTS.md and README with branch changes

Reflect new features and architecture added in this branch:
- Ruby 4.0.1 / Rails 8.2, UUIDv7 primary keys
- Testimonials, Projects, StarSnapshots models
- Community map, cross-domain auth, newsletter system
- LocationNormalizer, TimezoneResolver, MetadataFetcher services
- Brakeman added to pre-commit hooks
- Multi-domain setup documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: update README and AGENTS.md titles for both domains

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Move article draft to docs/articles with links and images

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix 404 for /community paths on rubycommunity.org

The /:id catch-all on the community domain was treating "community" as
a username lookup, which doesn't exist. Add 301 redirects for
/community and /community/:id within the community domain constraint
so stale links resolve correctly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix icons

* Fix sorting on profile page

* Improve Turbo navigation on community pages

Add turbo-action=advance to community list frame so filtering updates
the URL. Wrap profile tabs in a turbo-frame so project sorting navigates
without a full page reload.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Sync username and email on GitHub data refresh

Previously, username and email were only set during initial account
creation. If a user renamed their GitHub account, the app would keep
the stale username — breaking API calls and showing outdated profiles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant